Adsense

Showing posts with label stored procedure. Show all posts
Showing posts with label stored procedure. Show all posts

Saturday, November 15, 2014

How to Write own Java user-defined functions in DB2 & call UDFs in DB2 SQL with Example Step by Steps

            User Defined Functions (UDFs) are own functions written by the user which can be used in SQL, DDL or DML statements. UDfs can be written in two ways on DB2 Universal Database. One is SQL UDFs which is based on procedural extensions to the SQL language, highly used by other DBMS. The Other one is External UDFs which is written host languages like Java and others. Now let us write a user defined function in Java which can be used in in SQL. For example, In oracle INITCAP function returns the first letter of each word in uppercase, all other letters will be in lowercase. This function may not be available in DB2. Now we can write this function in Java can be used in DB2 .

Steps involved to write, deploy and run the UDFs

1. Write program for initCaps in Java

import java.io.*;
import java.io.*;
public class initCaps
{
public static String firstCaps(String line)  throws IOException 
{
 StringReader in = new StringReader(line); 
 boolean isNextCharSpace = true;
 StringBuffer proper = new StringBuffer();    
int i=0;
     while((i=in.read())!=-1) 
 {      
      char c = (char)i;      
      if (c == ' ')  {      proper.append(c);      isNextCharSpace = true;     } 
......
.....
}
}


Now compile the above program .
E:\DB2\IBM\SQLLIB\java\jdk\bin> javac initCaps.java

You can have more function in the same java file. Please ensure the java file is compiled and running using the same java version.

Covert the class file to Jar file by using the following command
jar cf myjar6.jar initCaps.class

Now register the jar file in DB2 using the following steps
Open the DB2 command prompt , then run the following command

CALL SQLJ.INSTALL_JAR('file:E:\DB2\IBM\SQLLIB\java\jdk\bin\myjar6.jar',testjar);

      By running the above command, the testjar.jar is file is copied to E:\DB2\IBM\SQLLIB\FUNCTION\jar\Schema Name\

Now Create a user-defined function in Db2 using Create Function



CREATE FUNCTION firstCaps(source varchar(3000)) RETURNS varchar(3000) LANGUAGE JAVA DETERMINISTIC NO SQL NOT FENCED EXTERNAL NAME 'testjar:initCaps!firstCaps' PARAMETER STYLE JAVA NO EXTERNAL ACTION

              where firstCaps is the function name which accepts string variable and returns a string variable. testjar is the jarfile name. initCaps is the Class file name. Again firstCaps used in External Name is the Java Method name. The string variable passed to the firstCaps function is passed to Java Method then processed and returns the Proper case of the string.

Now let us write the SQL query using the above user defined function.

select SchemaName.firstCaps(empname) from emp

Some of the Trouble shooting :

         You may get the error : SQL4301N Java or .NET interpreter startup or communication failed, reason code "0". SQLSTATE=58004
          Please check JDK_PATH by the command

In windows :             db2 get dbm cfg | find "JDK".
In Linux :               db2 get dbm cfg | grep -i JDK


The JDK_PATH is one level up to bin directory. So Update the path using the following command.

db2 update dbm cfg using JDK_PATH = E:\DB2\IBM\SQLLIB\java\jdk

           If the above error with reaon code "4" means you can check JAVA_HEAP_SZ. It should be enough to handle the User Defined function / Stored Procedure. 512 may be enough to handle. You can change the value using the following command.

db2 update dbm cfg using JAVA_HEAP_SZ 4096

Java stored procedure or user-defined function could not load Java class reason code "1". SQLSTATE=42724

Class Name mentioned in the Create Function may be mis-spelled. This error may be generated using java.lang.UnsupportedClassError. You have to ensure you are compiling and running the java class file using the same jdk version. Error may be seen E:\DB2\IBM\SQLLIB\DB2\db2dialog.log.

If No errors, then the statement select SchemaName.firstCaps(empname) from emp will give the output. Suppose the database having the employee names akash kumar, Micky jen, jackson Durai.

The output will be
Akash Kumar
Micky Jen
Jackson Durai

Monday, November 10, 2014

How to call db2 stored procedure from java program with example?

JDBC provides three statement interface which is used to send an SQL statement to the database server.

1. Statement
2. PreparedStatement which extends Statement
3. CallableStatement which extends PreparedStatement

Vendors of JDBC Driver provide classes that implement the above interfaces. Without a JDBC driver, you cannot create objects based on these interfaces. Database connection is required to to create statement object. This tutorial explains about CallableStatement objects and also how to call a DB2 stored procedure from a java application. Please go through my earlier post on how to create stored procedure in db2. Stored procedure can be called using the SQL CALL statement in DB2. Now how to call the stored procedures located on the database server from your Java application?

Using CallableStatement interface in java:

      CallableStatement object enable you to call and execute stored procedures stored on the database server from your Java application. Three types of JDBC parameters are there. They are IN, OUT, and INOUT

1. IN - parameters used for input. You can set values to IN parameters with the setXXX() methods.
2. OUT - result parameter used for output which returns output value of the stored procedure.
3. INOUT - parameter used for both input and output values parameters

A question mark (?) symbol serves as a placeholder for a parameter. The call to invoke the Stored procedure is written in an JDBC escape syntax that may take the followings forms

1. {call procedure_name[(?, ?, ...)]} - which accepts input parameters but no result parameter
2. {? = call procedure_name[(?, ?, ...)]} which returns a result parameter
3. {call procedure_name} - for no input / output parameters

A CallableStatement can return one or multiple ResultSet objects. Multiple ResultSet objects are handled using operations inherited from Statement.
                            cstmt.getMoreResults(); -used to point to the second or next result set.

Now let us see the steps to create a CallableStatement Object. Before creating it, let us create a stored procedure in DB2. In our example, I have created two Stored procedures in db2.

Ist Stored Procedure (SP) example : to return all records matching with a given salesman_id and date of sale
      input - salesmanid, sales_date
      output - result set (salesman_id, salesman, item_name , sales_date, sales_amt)

Stored Procedure for the above problem is given below

Stored Procedure I:
    
CREATE PROCEDURE  ItemSalesBy (salesmanid  varchar(5), dateofsale date)     SPECIFIC sp10    DYNAMIC RESULT SETS 1 
P1: BEGIN
    DECLARE cursor1 CURSOR WITH RETURN FOR   select salesman_id, (select c.name from salesman c where c.salesman_id=b.salesman_id) SalesMan,  (select a.item_name from item_master a where a.item_code=b.item_code) ItemName, sales_date, sales_amt from salesmantxn b  where b.salesman_id=salesmanid and b.sales_date=dateofsale;
    OPEN cursor1;
END P1 
@


We can create and call (execute) the above stored procedure using command line processor (CLP) and through java program.

To create stored procedure using CLP, store above stored procedure in a file . for example salesman.sql . Now run the following commands

db2 connect to test
db2 -td@ -vf salesman.sql


to call the above SP through CLP

db2 call ItemSalesBy('101','2012-02-25'), where 101 is the salesman id, 2012-02-25 is the date of sale
Now let us create and call (execute) the above stored procedure using java program

To create CallableStatement object, the following statements are used

CallableStatement cstmt = null;
cstmt = conn.prepareCall ("{ call ItemSalesBy(?,?)}"); 
// Callablestatement object to call the stored procedure

           where ItemSalesBy is the SP name and two question mark (?,?) is used to pass input parametters. In our example, salesman_id , sales_date. The following java program drops the existing SP named ItemSalesBy and creates the same SP and executes with the given input parameters. The statement

              ResultSet rs = cstmt.executeQuery();       returns the result set returned by the SP.
    

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;

public class CSPRS2 {
    static Connection conn; 
    public static void main(String[] args) {
     
       try {
                    //Class.forName("COM.ibm.db2.jdbc.app.DB2Driver");

                      Class.forName("com.ibm.db2.jcc.DB2Driver");

} catch (ClassNotFoundException e) 

                  {
                     e.printStackTrace();

                     return;

                   }

       try
        {
               conn = DriverManager.getConnection("jdbc:db2:test");
            }
        catch( Exception e )
        {
            e.printStackTrace();
            System.exit(1);
        }


  //  dropSP(); // to drop procedure if already exists  

    createSP();  // to create stored procedure (SP)


    callSP("101", "2012-02-25"); // to execute SP
    }


   private static void dropSP() {
        String str=null;
        Statement stmt = null;
        try 
        {
            stmt = conn.createStatement();
           str="drop procedure ItemSalesBy";
            stmt.executeUpdate (str);
        } 
        catch (SQLException e1) 
        { e1.printStackTrace();}
       }

 

  private static void createSP() {
        String strSP=null;
        Statement stmt = null;

   strSP="CREATE PROCEDURE  ItemSalesBy (salesmanid  varchar(5), dateofsale date)  SPECIFIC sp10    DYNAMIC RESULT SETS 1 \n" +
             "P1: BEGIN \n" +
             "DECLARE cursor1 CURSOR WITH RETURN FOR   select salesman_id, (select c.name from salesman c  where c.salesman_id=b.salesman_id) SalesMan,  (select a.item_name from item_master a where a.item_code=b.item_code) ItemName, sales_date, sales_amt from salesmantxn b  where  b.salesman_id=salesmanid and b.sales_date=dateofsale; \n" +
             "OPEN cursor1; \n" +
              "END P1 \n";
   

     try
        {
            stmt = conn.createStatement();
            stmt.executeUpdate (strSP);
            System.out.println("Stored Procedure created successfully\n");
        }
        catch (SQLException e)
        {
            System.out.println("Error in creating SP: " + e.toString());
            System.exit(1);
        }  
    }


    private static void callSP(String sid, String sdate) 
    {
        CallableStatement cstmt = null;
        try 
        {
            cstmt = conn.prepareCall ("{ call ItemSalesBy(?,?)}");  // CallableStatement object  to call the stored procedure 
            cstmt.setString(1,sid);
            cstmt.setDate(2, java.sql.Date.valueOf(sdate));
            ResultSet rs = cstmt.executeQuery();
            System.out.println("SALESMAN_ID SALESMAN              ITEMNAME      SALES_DATE    SALES_AMT\n");
            System.out.println("----------- ---------------- ------------------- ----------  ------------\n");
         

   if (rs != null) {        

          while (rs.next())
           {
             System.out.println(rs.getInt(1) + "             " + rs.getString(2) + "       " + rs.getString(3) + "      " + rs.getString(4) +"       "+rs.getString(5));
            }
           }
        } 
        catch (SQLException e) 
        {
            e.printStackTrace();
        }
    }
}
Output :


Stored Procedure II: To calculate wages for a salesman on a particular date based on sales_amt. wages is calculated with the following formula wages = total_sales_amt * 0.5 /100 + bonus ; and Rs. 100 bonus is added if the sales_amt &gt;10000 and sales_amt<=200000, Rs. 200 bonus if sales_amt>200000 and sales_amt<=300000 , Rs. 300/- bonus if sales_amt>300000 IN Parameter : salesman_id, Sales_date OUT parameter : wages Stored Procedure for the above problem is given below

    
CREATE PROCEDURE wagesCalc(IN salesmanid varchar(5),IN SalesDate date , OUT  wages  double)   LANGUAGE SQL
  BEGIN
     DECLARE bonus double;
     DECLARE sumsales double;
     DECLARE wages_temp double;
     DECLARE cursor1 CURSOR FOR SELECT SUM(SALES_AMT),  SUM(SALES_AMT)*0.5/100 FROM SALESMANTXN where SALESMAN_ID=salesmanid  and SALES_DATE=SalesDate;
      SET bonus= 0;
     OPEN cursor1;
     FETCH FROM cursor1 INTO sumsales, wages_temp;
    
  IF (sumsales&gt;300000) THEN
     set bonus=300;
  ELSEIF (sumsales&gt;200000 and sumsales<=300000) THEN
     set bonus=300;
  ELSEIF (sumsales&gt;100000 and sumsales<=200000) THEN
    set bonus=100;
  END IF;
     CLOSE cursor1;
 SET wages = wages_temp+ bonus; 
 END%  

               to create above SP using CLP , store above stored procedure in a file . eg. wages.sql . Now run the following commands db2 connect to test db2 -td% -vf wages.sql to call the above SP through CLP db2 call wagesCalc('101', '2012-02-25', ?), which returns wages for the saleman_id=101 and sales_date='2012-02-25' Now let us see how to call (execute) the above stored procedure using java program

     private static void callSP(String sid, String sdate) 
        {
          Double wages=0.0;
          CallableStatement cstmt = null;
        try 
        {
            cstmt = conn.prepareCall ("{ call wagesCalc(?,?,?)}");  // CallableStatement object  to call the stored procedure 
            cstmt.setString(1,sid);
            cstmt.setDate(2, java.sql.Date.valueOf(sdate));
            cstmt.registerOutParameter(3, Types.DOUBLE);
            cstmt.execute();
            wages  = cstmt.getDouble(3);
               System.out.println("Sales Man Id = " + sid  + " Wages= " + wages);
        } 
        catch (SQLException e) 
        {
            e.printStackTrace();
        }
    } 
         
   Output of the above program : 

D:\as2\JF5>java CSPRS4 Sales Man Id = 101 Wages= 650.0

          In the above program, registerOutParameter(3, Types.DOUBLE); Registers the OUT parameter in ordinal position parameterIndex to the JDBC type sqlType The execute() returns boolean value. if it returns false means, first result is an update count or there is no result; true means, the first result is a ResultSet object

Thursday, March 28, 2013

Stored Procedure in db2 and benefits. Create Procedure command with example

A stored procedure is a subroutine that can be called by an application with an SQL CALL statement . A stored procedure is stored in the database itself. Stored Procedures are invoked by executing the CALL statement with a reference to a procedure. The storedprocedure can be called locally or remotely. 


Avoidance of network traffic :
 In client server architecture, applications access the remote database over the network. This results in poor performance because it returns a lot of unnecessary data to the client. But when using stored procedure, as stored procedure runs on the server, only the results the client application needs are returned. This reduces the network traffic, also Stored Procedures groups SQL statements together which can also save on network traffic. A typical application requires two trips across the network for each SQL statement. Grouping of SQL statements reduces the trips across the network which results in better performance for applications. 

Access to features that exist only on the server : Stored procedures can have access to commands that run only on the server, such as LIST DB DIRECTORY and LIST TABLES. It can take the advantages of increased memory and disk space on server machines and they can access any additional software installed on the server.

Define Business rules common to several application : You can use stored procedures to define business rules that are common to several applications similar to triggers and constraints. When an application calls the stored procedure, it will process data based on the rules defined in the stored procedure. If you need to change the rules, you only need to make the change once in the stored procedure, not in every application that calls the stored procedure.

Protection from SQL injection attacks: Stored procedures reduces the risk of sql injection attacks. Stored procedure parameters will be treated as data even if an attacker inserts SQL commands

Helps for workload distribution: It splits the application logic and encourages an even distribution of the computational workload.Stored procedures can be developed using DB2 development center (in db2 8.2) , a GUI based or you can create using CLP . Now let us see how to create and run a Stored Procedures using Command Line Processor (CLP ) . 

Example 1 : Stored Procedure to filter job seekers applications based on the conditions like Date of Birth of the candidate should be between the given two input dates and qualification should be equal to the given input string. The Stored Procedure will accept three input parameters MinDate , MaxDate and Qualification. Output will be the result sets. 

 
CREATE PROCEDURE Shortlist (mindate date , maxdate date, qual  varchar(20))     SPECIFIC sp5    DYNAMIC RESULT SETS 1 
P1: BEGIN
    DECLARE cursor1 CURSOR WITH RETURN FOR   select * from applications where dob>=mindate and dob<=maxdate and qualification=qual;
    OPEN cursor1;
END P1 
@

Store the above lines in a file named sp1.sql. If you run the above script file using the command 
                         db2 -tvf sp1.sql,
                          you may get the error like    DB21028E The cursor "CURSOR1" has not been declared. DB21007E End of file reached while reading the command. 

To solve the above error, select an alternate terminating character for the Command Line Processor (DB2 CLP), other than the default terminating character which is semicolon (;) , to use in the script. For example, the above create procedure statement, @ is used as a terminating character. Now run the DB2 CLP script containing the CREATE PROCEDURE statement from the command line, using the following CLP command:

db2 -td <terminating-character> -vf <CLP-script-name> 

       to run the above Stored Procedure, issue the command 
          db2 -td@ -vf sp1.sql 
                               where @ is a terminating character for the procedure. Now the Stored Procedure (sp1.sql) is created. To run the above stored procedure , issue the command 

db2 call Shortlist('1970-01-01', '1980-01-01', 'BE') ,

      running the command returns all the records whose dob<='1970-01-01' and dob<='1980-01-01' and qualification='BE'

Example 2 : To update employee's salary based on the grade.  Accepts input employee code and grade . 

 
CREATE PROCEDURE SALARY_UPDATE  (IN emp_code varchar(10), IN grade SMALLINT)    LANGUAGE SQL
    BEGIN
      DECLARE error CONDITION FOR SQLSTATE '02000';
      DECLARE EXIT HANDLER FOR error  SIGNAL SQLSTATE '20001' SET MESSAGE_TEXT = 'Employee code does not exist';
      IF (grade = 1)  THEN UPDATE emp3   SET salary = salary + (salary*15/100)   WHERE empcode= emp_code;
      ELSEIF (grade = 2)   THEN UPDATE emp3     SET salary = salary + (salary*10/100)   WHERE empcode= emp_code;
      ELSEIF (grade=3) THEN UPDATE emp3   SET salary = salary + (salary*5/100)    WHERE empcode= emp_code;
      END IF;
    END
@   

Store the above script in a file named sp2.sql

Run the above script by the command 
                           db2 -td@ -vf sp2.sql.            and run the procedure by 
                            db2 call SALARY_UPDATE('1132', 1)   
                                         -where empcode is 1132 and grade is 1.  So the salary will be updated by 15% increment. 

Suppose the employee code does not exist in the table , then the default error
                SQL0100W No row was found for FETCH, UPDATE or DELETE; or the result of a query is an empty table. SQLSTATE=02000      will be thrown. 

  SQLSTATE is 02000 

Now we can change the default error message with own error message like Employee code does not exist . . For the the following lines are used. error variable is declared, if the SQLSTATE=02000. For that error, we are setting a new message as "Employee code doe not exist" and SQLSTATE as 20001.

DECLARE error CONDITION FOR SQLSTATE '02000'; 

DECLARE EXIT HANDLER FOR error SIGNAL SQLSTATE '20001' SET MESSAGE_TEXT = 'Employee code doe not exist'; .  So the following error will be thrown, if no records found. 

SQL0438N Application raised error with diagnostic text: "Employee code does not exist". SQLSTATE=20001

Example 3 : The above two stored procedures return the result sets as output. Now let us see the a different example , to calculate sum of salaries of a particular employee's whose designation matches the given input string . (for eg. UDC , LDC, ...)

 
CREATE PROCEDURE totalsalary(IN Desig char(20)  , OUT totalsalary INTEGER)   LANGUAGE SQL
  BEGIN
    DECLARE SQLSTATE CHAR(5) DEFAULT '00000';
    DECLARE tot_sal INTEGER;
    DECLARE empsalary INTEGER;
    DECLARE cursor1 CURSOR FOR SELECT SALARY FROM EMP3 where Designation=Desig;
      SET tot_sal= 0;
     OPEN cursor1;
     FETCH FROM cursor1 INTO empsalary;
     WHILE(SQLSTATE = '00000') DO
        SET tot_sal = tot_sal+ empsalary;
        FETCH FROM cursor1 INTO empsalary; 
     END WHILE;
     CLOSE cursor1;
     SET totalsalary=tot_sal;
  END%

In the above script, termination charater is %, so run the script with command 
                                db2 -td% -vf sp3.sql
            It accepts two parameters. One is for input , another is for output. We have set SQLSTATE to '00000'. So the while loop continues until the SQLSTATE changes. The SQLSTATE changes when the cursor has no further rows. when there is no rows , it throws exception with SQLSTAT 02000. Now the while loop terminates.